/**
 * cookie utils of system
 * @author lms 2022.07.21
 */

package ms.core.gateway.tool;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.Data;
import ms.core.gateway.system.Application;
import ms.core.tool.EncryptTool;
import ms.core.tool.StrTool;
import ms.core.tool.SysTool;

public class CookieTool {
    final public static String COOKIE_SESSIONID = "sid";    		// 会话Id
    final public static String COOKIE_CORPID	= "cid";			// 企业id
    final public static String COOKIE_USER_ID   = "uid";        	// 用户帐号guid
    final public static String COOKIE_ACCOUNT   = "uat";        	// 用户帐号
    final public static String COOKIE_NICK 	   	= "nck";        	// 帐号昵称
    final public static String COOKIE_TOKEN 	= "said";    		// 访问授权码(sid + uid + uat)

    /**
     * to get sessionId from cookie
     *
     * @param req
     * @return
     */
    public static String getSid(HttpServletRequest req) {
    	//Session().getId 操作会导致tomcat建立默认会话(会话由框架维护,所以不采用此方式)
    	return getCookieValue(req, COOKIE_SESSIONID);
    }
    
    /**
     * 生成加密的 token
     * 
     * @param sid
     * @param corpId
     * @param uid
     * @param uname
     * @return
     */
    private static String makeToken(String sid, String corpId, String uid, String uname) {
    	return EncryptTool.sha1(StrTool.concat(Application.APP_NAME, Application.KEY_SALT, sid, corpId, uid, uname));    	
    }

    /**
     * to get sessionId from cookie,if not exists, return new session Id
     * 应用场景:获取验证码,需要设置sid到cookie,同时sid需保存到session里
     *
     * @param req
     * @param resp
     * @return
     */
    public static String getSid(HttpServletRequest req, HttpServletResponse resp) {
    	//Session().getId 操作会导致tomcat建立默认会话(会话由框架维护,所以不采用此方式)
    	String sid = getCookieValue(req, COOKIE_SESSIONID);
    	if (StrTool.isBlank(sid)) {
    		sid = "sid."+SysTool.makeUUID("");
    		setCookieValue(resp, COOKIE_SESSIONID, sid, true);
    	}

    	return sid;
    }

    /**
     * 设置用户登录成功cookies
     *
     * @param response
     * @param ck
     */
    public static Cookies setLoginCookies(HttpServletResponse resp, String sid, String corpUid, String userUid, String account, String nick) {
    	Cookies cks = new Cookies();
    	// set session id
    	setCookieValue(resp, COOKIE_SESSIONID, sid, true);
    	cks.setSid(sid);
    	// set corp id
    	setCookieValue(resp, COOKIE_CORPID, corpUid, true);
    	cks.setCid(corpUid);
    	// set user id
    	setCookieValue(resp, COOKIE_USER_ID, userUid, true);
    	cks.setUid(userUid);
        // set user account
    	setCookieValue(resp, COOKIE_ACCOUNT, account, true);
    	cks.setAct(account);
        // set user nick
    	setCookieValue(resp, COOKIE_NICK, nick, true);
    	cks.setNck(nick);
        // set token
    	String said = makeToken(sid, corpUid, userUid, account);
    	setCookieValue(resp, COOKIE_TOKEN, said, true);
    	cks.setSaid(said);
    	
    	return cks;
    }

    /**
     * to clear login cookie
     *
     * @param response
     */
    public static void invalidCookie(HttpServletResponse response) {
        invalidCookie(response, COOKIE_CORPID);
        invalidCookie(response, COOKIE_USER_ID);
        invalidCookie(response, COOKIE_ACCOUNT);
        invalidCookie(response, COOKIE_NICK);
        invalidCookie(response, COOKIE_TOKEN);
    }

    /**
     * 检查 request 请求是否属于登录状态
     * 
     * @param req
     * @return
     */
    public static boolean logined(HttpServletRequest req) {
    	String sid    = getCookieValue(req, COOKIE_SESSIONID);
    	String corpId = getCookieValue(req, COOKIE_CORPID);
    	String uid    = getCookieValue(req, COOKIE_USER_ID);
    	String uname  = getCookieValue(req, COOKIE_ACCOUNT);
    	String token  = getCookieValue(req, COOKIE_TOKEN);
    	if (StrTool.isBlank(sid) || StrTool.isBlank(uid) || StrTool.isBlank(uname) || StrTool.isBlank(token))
    		return false;
    	
    	return token.equals(makeToken(sid, corpId, uid, uname));
    }

    /**
     * to get cookie from httpRequest by cookie id
     *
     * @param request
     * @param cookieName cookie name of value
     * @return null if cookie not exists, otherwise return value of cookie
     */
    private static String getCookieValue(HttpServletRequest request, String cookieName) {
        cookieName = Application.APP_NAME + cookieName;
        Cookie[] cookies = request.getCookies();
        if (cookies == null || cookies.length==0) return null;

        for (Cookie ck: cookies) {
            if (ck.getName().equals(cookieName)) {
                return EncryptTool.httpDecode(ck.getValue(), Application.UTF8);
            }
        }

        return null;
    }

    /**
     * 设置cookie
     *
     * @param response   response to client
     * @param cookieName cookie name to set
     * @param value      cookie value of cookie name
     * @param readOnly   readonly cookie
     */
    private static void setCookieValue(HttpServletResponse response, String cookieName, String value, boolean readOnly) {
        //设置cookie
    	cookieName = Application.APP_NAME + cookieName;
        Cookie ck = new Cookie(cookieName, EncryptTool.httpEncode(value,Application.UTF8));
        ck.setMaxAge(Application.SESSION_EXPIRY * 60);
        ck.setHttpOnly(readOnly);
        response.addCookie(ck);
    }

    private static void invalidCookie(HttpServletResponse response, String cookieName) {
        cookieName = Application.APP_NAME + cookieName;
        Cookie ck = new Cookie(cookieName, null);
        ck.setMaxAge(0);
        response.addCookie(ck);
    }

    @Data
    public static class Cookies {
    	private String sid;			// session id
    	private String cid;			// corp id
    	private String uid;			// user account id
    	private String act;			// user account
    	private String nck;			// user nick
    	private String said;		// token
    }    
}
